from zope.interface import implements

from twisted.internet import reactor, defer
from twisted.application import service

from pyhsrv import interfaces, errors, net

import socket, time

class FakeNodeService(service.Service):

    implements(interfaces.IFakeNodeService)

    def __init__(self, db, servername):
        """Collecting the metadata about the nodes, plugins"""
        
        self.db = db
        self.conns = {}
        self.authed = []
        self.nodes = {}
        self.parents = {}
        self.servername = servername
        self.itret = {}
        self.plret = {}
        self.valret = {}
    
        d1 = self.db.getNodes_by_name(self.servername, session=True)
        def fill_nodes(nodes):
            self.nodes = nodes
        d1.addCallback(fill_nodes)
        d1.addErrback(errors.catchError)
        d2 = self.db.getParents(self.servername, session=True)
        def fill_parents(parents):
            for p in parents:
                self.parents[p.name] = socket.gethostbyname(p.addr)
        d2.addCallback(fill_parents)
        d2.addErrback(errors.catchError)
       
    def parseMsg(self, msg, p_inst):
        cmd, params = msg.split(' ')[0], msg.split(' ')[1:]
        if p_inst in self.authed:
            if cmd == "get" and len(params) == 3:
                if self.nodes[params[0]].has_key(params[1]):
                    d = self.db.getNodeStatus(params[0], session=True)
                    def addName(name_and_status):
                        np = params[0] + ":" + params[1]
                        self.valret[np] = "values " + name_and_status + " "
                        self.valret[np] += params[1] + " "
                        d2 = self.db.getValuesForPlugin(params[0], params[1],\
                                                   params[2], session=True)
                        def format_msg(values, np):
                            if values != None:
                                for it in values.keys():
                                    self.valret[np] += it + ":"
                                    for v in values[it]:
                                        self.valret[np] += str(v[0]) + ',' + \
                                            str(v[1]) + ';'
                                    self.valret[np] = self.valret[np][:-1] + "|"
                                return self.valret[np][:-1]
                            else:
                                return None
                        d2.addErrback(errors.catchError)
                        d2.addCallback(format_msg, np)
                        return d2
                    d.addErrback(errors.catchError)
                    d.addCallback(addName)
                    return d
            
            elif cmd == "getnodes":
                d = self.db.getNodesWithStatus(self.servername, session=True)
                def format_nodes_msg(nodes_and_status):
                    ret = "nodes"
                    for n in nodes_and_status.keys():
                        ret += " " + n + ":" + str(nodes_and_status[n])
                    return ret
                d.addErrback(errors.catchError)
                d.addCallback(format_nodes_msg)
                return d
                

            elif cmd == "getplugins" and len(params) == 1:
                if self.nodes.has_key(params[0]):
                    n = params[0]
                    self.plret[n] = "plugins " + params[0]
                    def formatMsg(p):
                        self.plret[n] += " " + p['name'] + ":" 
                        self.plret[n] += str(p['vtype']) + ","
                        self.plret[n] += str(p['delay']) + ","
                        self.plret[n] += str(p['buffered']) + "," 
                        self.plret[n] += '|'.join(str(p['title']).split(' '))
                    def returnIt(x):
                        return self.plret[n]
                    d = defer.succeed("")
                    for p in self.nodes[n].keys():
                        d.addCallback(self.db.getPlugin_by_name, params[0], \
                                      p, session=True)
                        d.addErrback(errors.catchError)
                        d.addCallback(formatMsg)
                        d.addErrback(errors.catchError)
                    d.addCallback(returnIt)
                    d.addErrback(errors.catchError)
                    return d

            elif cmd == "getitems" and len(params) == 2:
                node = params[0]
                plug = params[1]
                
                if self.nodes.has_key(node):
                    if self.nodes[node].has_key(plug):
                        np = node + ':' + plug
                        self.itret[np] = "items " + node + ":" + plug
                        def formatMsg(i):
                            self.itret[np] += " " + str(i['name']) + ":" 
                            self.itret[np] += str(i['stype']) + "," 
                            self.itret[np] += str(i['label']) + "," 
                            self.itret[np] += str(i['cdef']) + ","
                            self.itret[np] += str(i['draw']) + ","
                            self.itret[np] += str(i['amin']) + ","
                            self.itret[np] += str(i['amax'])
                        def returnIt(x):
                            return self.itret[np]
                        d = defer.succeed("")
                        for i in self.nodes[node][plug]:
                            d.addCallback(self.db.getItem, node, plug,\
                                          i, session=True)
                            d.addErrback(errors.catchError)
                            d.addCallback(formatMsg)
                            d.addErrback(errors.catchError)
                        d.addCallback(returnIt)
                        d.addErrback(errors.catchError)
                        return d
            
            else:
                return defer.succeed("The '" + cmd + \
                                     "' command is not implemented yet.")
        
        elif cmd == "hello" and len(params) == 1:
            if params[0] == self.servername:
                return defer.succeed("you are?")

        elif cmd == "i'm" and len(params) == 1:
            if self.parents.has_key(params[0]):
                if self.parents[params[0]] == self.conns[p_inst]['ipaddr']:
                    self.authed.append(p_inst)
                    return defer.succeed("hello, it's " + str(time.time()))
                return defer.succeed(None)
         
        else:
            return defer.succeed("don't be rude, say hello")
        
        return defer.succeed(None)


    def newConnection(self, p_inst, ipaddr):
        """For state machines, maybe in the future..."""
        self.conns[p_inst] = {}
        self.conns[p_inst]['ipaddr'] = ipaddr

    def closeConnection(self, p_inst):
        if p_inst in self.authed:
            self.authed.remove(p_inst)
        try:
            del self.conns[p_inst]
        except:
            pass
